// EdgeServer.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <WinSock2.h>
#include "Command.h"
#include <assert.h>
#include <WS2tcpip.h>
#include <vld.h>
#include <thread>
#include "../EdgeMath/Vectors.h"
#include "../EdgeRemote/NetworkDefs.h"
#include "../EdgeGameCore/World/Chunk.h"
#include <atomic>
#include <map>
#pragma comment(lib, "Ws2_32.lib")

static std::atomic<bool> running = true;
std::vector<Command> commands;
SOCKET listenSocket = INVALID_SOCKET;
std::thread* main_thread = nullptr;

#define cast(ptr, type) reinterpret_cast<type*>(ptr)

std::map<Vector2, Chunk*> chunks;

void quit()
{
	running = false;
}

void update_server(void);
void init_server(void);
void run_server(void);

void print_funcs()
{
	std::cout << '\n';
	for (unsigned int i = 0; i < commands.size(); i++)
		std::cout << commands[i].name << " - " << commands[i].description << '\n';
}

void open_server(void)
{
	if (main_thread)
	{
		std::cout << "Server has already been started" << std::endl;
		return;
	}
	WSADATA data;
	int result = WSAStartup(MAKEWORD(2, 2), &data);
	assert(result == 0 && "Failed to inilitize server");

	addrinfo address_info;
	PADDRINFOA localAddressInfo = nullptr;
	ZeroMemory(&address_info, sizeof(addrinfo));
	address_info.ai_family = AF_INET;
	address_info.ai_socktype = SOCK_STREAM;
	address_info.ai_protocol = IPPROTO_TCP;
	address_info.ai_flags = AI_PASSIVE;

	result = getaddrinfo(NULL, DEFAULT_PORT, &address_info, &localAddressInfo);
	assert(result == 0 && "Failed to get local address info");

	listenSocket = socket(localAddressInfo->ai_family, localAddressInfo->ai_socktype, localAddressInfo->ai_protocol);
	assert(listenSocket != INVALID_SOCKET && "Failed to create socket");

	result = bind(listenSocket, localAddressInfo->ai_addr, (int)localAddressInfo->ai_addrlen);
	assert(result == 0 && "Failed to bind socket");

	FreeAddrInfoA(localAddressInfo);

	main_thread = new std::thread(run_server);
}

int _tmain(int argc, _TCHAR* argv[])
{
	std::cout << "****** Edge Server *******************\n\n";
	std::cout << "Type \'help\' for command list\n\n";
	std::cout << "**************************************\n\n\n";

	commands.push_back(Command("quit", quit, "Exits the application"));
	commands.push_back(Command("help", print_funcs, "Prints the names of all functions"));
	commands.push_back(Command("start", open_server, "Starts running the server"));	
	
	while (running)
	{
		std::string line;
		std::getline(std::cin, line);
		for (unsigned int i = 0; i < commands.size(); i++)
		{
			if (commands[i].name == line)
				commands[i].function();
		}
	}

	WSACleanup();
	if (listenSocket != INVALID_SOCKET)
		closesocket(listenSocket);

	if (main_thread)
	{
		main_thread->join();
		delete main_thread;
	}

	return 0;
}

void run_server(void)
{
	init_server();
	update_server();
}

void init_server(void)
{
	// establish connections with clients
	int result = listen(listenSocket, SOMAXCONN);
	if (result == SOCKET_ERROR)
	{
		std::cout << "Socket was unable to listen for connections. Winsock Error code: " << WSAGetLastError() << std::endl;
		closesocket(listenSocket);
		return;
	}
	// create game world

	std::cout << "Loading game world..." << std::endl;

	chunks[vector_2::Zero] = new Chunk("Content/xml/betaLevel.xml");


	std::cout << "\nServer started successfully\n" << "Listining on port " << DEFAULT_PORT << "...\n";

}

void update_server(void)
{
	while (running)
	{
	}
}

